//
//  ECScriptContext.m
//  ECDevelopKit
//
//  Created by LittoCats on 8/6/14.
//  Copyright (c) 2014 Littocats. All rights reserved.
//

#import "ECSScriptContext.h"
#import "NSObject+ECS.h"
#import "ECSJavaScriptContext.h"

#import <objc/message.h>

#import "ECSJavaScriptFunction.h"
@interface ECSJavaScriptFunction (ECSScriptContext)<ECSScriptFunction>

@end

@interface ECSScriptContext ()

@property (nonatomic, strong) ECSJavaScriptContext *JavaScriptContext;

@end

@implementation ECSScriptContext

+ (instancetype)context
{
    ECSScriptContext *context = [[ECSScriptContext alloc] init];
    //载入默认 api
    static NSString *ecs_script_api_default = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        ecs_script_api_default = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ecs_script_api_default"
                                                                                                                    ofType:@"js"]
                                                                           encoding:NSUTF8StringEncoding
                                                                              error:nil];
        NSAssert(ecs_script_api_default, @"[ECSViewController] error : ecs_script_api_default not exist .");
    });
    [context evaluateScript:ecs_script_api_default];
    return context;
}

- (id)evaluateScript:(NSString *)script
{
    return script && ![script isEmpty] ? [_JavaScriptContext evaluateJavaScript:script] : nil;
}

- (id)callFunction:(id)function withArguments:(id)argument, ...
{
    va_list arglist;
    va_start(arglist, argument);
    return [self callFunction:function withArgument:argument va_list:arglist];
}

+ (id)callFunction:(id<ECSScriptFunction>)function withArguments:(id)argument, ...
{
    va_list arglist;
    va_start(arglist, argument);
    return [function evaluateWithArguments:argument va_list:arglist];
}
- (id)callFunction:(NSString *)function withArgument:(id)arg va_list:(va_list)arg_list
{
    return [_JavaScriptContext callFunction:function withArguments:arg va_list:arg_list];
}

- (id)dispatchApi:(NSString *)api argumnts:(NSArray *)arguments action:(NSMutableDictionary *)action completionHandler:(void (^)(id result))scriptHandler
{
     Class apiManager = NSClassFromString(@"ECSScriptApi");
    
    return objc_msgSend(apiManager, @selector(dispatchApi:argumnts:action:completionHandler:),
                    api ,
                    arguments,
                    action,
                    scriptHandler);
}


#pragma mark- 初始化及销毁
- (id)init
{
    self = [super init];
    if (self) {
        _JavaScriptContext = [[ECSJavaScriptContext alloc] init];
        
        [_JavaScriptContext addProperty:^(id arg,...){
            NSLog(@"[ECSScriptContext] log \n");
            printf("%s\t",[arg description].UTF8String);
            if (!arg) return;
            va_list vList;
            va_start(vList, arg);
            id va_arg = va_arg(vList, id);
            while (va_arg) {
                const char *info = [[va_arg description] UTF8String];
                printf("%s\t",info);
                va_arg = va_arg(vList, id);
            }
            printf("\n");
        } withName:@"__log"];
        
        [_JavaScriptContext addProperty:^void (id<ECSScriptFunction> function, NSNumber *delay){
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)([delay doubleValue]/1000.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [function evaluateWithArguments: nil];
            });
        }withName:@"setTimeout"];
        
        [_JavaScriptContext addProperty:^id (NSString *apiName, NSDictionary *apiArg, NSMutableDictionary *apiAction, ECSJavaScriptFunction *callBack){
            
            NSMutableArray *apiArguments = [NSMutableArray new];
            for (int index = 0; index < [apiArg count]; index ++) {
                [apiArguments addObject:apiArg[[NSString stringWithFormat:@"%i",index]]];
            }
            [apiAction setObject:[NSObject findObjectById:apiAction[ECSScriptContextKey]] forKey:ECSScriptContextKey];
            
            return [apiAction[ECSScriptContextKey] dispatchApi:apiName argumnts:apiArguments action:apiAction completionHandler:^(id result){
                [callBack applyWithArguments:result, nil];
            }];
        } withName:@"__ecs_script_api"];
        
#ifdef DEBUG
        [self evaluateScript:[NSString stringWithFormat:@"var _system='%@';var _lang='zh';var _debug=%@;var _pid='%@';",@"IOS", @"true", self._id]];
#else
        [self evaluateScript:[NSString stringWithFormat:@"var _system='%@';var _lang='zh';var _debug=%@;var _pid='%@'",@"IOS", @"false", self._id]];
#endif
        
        static NSString *ecs_script_lib = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSMutableString *m_string = [NSMutableString new];
            //加载jslib
            NSString *promise_js = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ecs_script_promise" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
            NSAssert(promise_js, @"[EC JavaScript Context] init error: load environment faild");
            [m_string appendString:promise_js];
            
            NSString *environment_js = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ecs_script_context" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
            NSAssert(environment_js, @"[EC JavaScript Context] init error: load environment faild");
            [m_string appendString:environment_js];
            
            //加载 api_builder
            NSString *apibuilder_js = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ecs_script_api_builder" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
            NSAssert(apibuilder_js, @"[EC JavaScript Context] init error: load environment faild");
            [m_string appendString:apibuilder_js];
            
            ecs_script_lib = [[NSString alloc] initWithString:m_string];
        });
        [self evaluateScript:ecs_script_lib];
    }
    return self;
}

@end

//************************************************************************************************************************//


@implementation ECSJavaScriptFunction (ECSScriptContext)

- (id)evaluateWithArguments:(id)argument, ...
{
    va_list arglist;
    va_start(arglist, argument);
    return [self evaluateWithArguments:argument va_list:arglist];
}

- (id)evaluateWithArguments:(id)argument va_list:(va_list)vList
{
    return [self applyWithArguments:argument va_list:vList];
}

+ (id)invokFunction:(id <ECSScriptFunction>)function arguments:(id)argument, ...
{
    va_list arglist;
    va_start(arglist, argument);
    return [function evaluateWithArguments:argument va_list:arglist];
}
@end